package frame

import (
	"gitee.com/lipore/go-nio/pkg/buffer"
)

type delimiterBasedFrameCodec struct {
	delimiter byte
	escaper   byte
}

func DelimiterBasedFrameCodec(delimiter byte, escaper byte) CodeC {
	return &delimiterBasedFrameCodec{
		delimiter: delimiter,
		escaper:   escaper,
	}
}

func (c *delimiterBasedFrameCodec) indexDelimiter(b []byte) (index int) {
	index = -1
	for i := 0; i < len(b); i++ {
		if b[i] == c.escaper {
			i++
			continue
		}
		if b[i] == c.delimiter {
			index = i
			break
		}
	}
	return
}

func (c *delimiterBasedFrameCodec) Decode(buffer *buffer.Buffer) (Frame, bool, error) {
	byts := buffer.Bytes()
	i := c.indexDelimiter(byts)
	if i == -1 {
		return nil, false, nil
	}
	f := make([]byte, i+1)
	_, err := buffer.Read(f)
	if err != nil {
		return nil, false, err
	}
	w := 0
	for r := 0; r < len(f); r++ {
		if f[r] == c.escaper {
			f[w] = f[r+1]
			r++
		}
		f[w] = f[r]
		w++
	}
	return f[:w-1], true, nil
}

func (c *delimiterBasedFrameCodec) Encode(f Frame) ([]byte, bool) {
	l := len(f)
	if l > 0 {
		buf := new(buffer.Buffer)
		for i := 0; i < l; i++ {
			if f[i] == c.delimiter || f[i] == c.escaper {
				buf.Write([]byte{c.escaper, f[i]})
			} else {
				buf.Write([]byte{f[i]})
			}
		}
		buf.Write([]byte{c.delimiter})
		return buf.Bytes(), true
	}
	return nil, false
}
